package com.touzhijia.authority.security;

import com.touzhijia.authority.utils.mapper.JacksonMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;

/**
 * 作者： lzw<br/>
 * 创建时间：2018-03-15 12:48 <br/>
 */
@Component
@Slf4j
public class UserLoginFilter extends AbstractAuthenticationProcessingFilter {

    private static final String USERNAME_KEY = "username";
    private static final String PASSWORD_KEY = "password";
    private static final String CAPTCHA_KEY = "captcha";

    @Autowired
    private SecurityConfig securityConfig;
    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
//    @Autowired
//    private SessionRegistry sessionRegistry;

    private String usernameParameter = USERNAME_KEY;
    private String passwordParameter = PASSWORD_KEY;
    private String captchaParameter = CAPTCHA_KEY;
    private boolean postOnly = true;


    public UserLoginFilter(SecurityConfig securityConfig) {
        super(new AntPathRequestMatcher(securityConfig.getLogin().getLoginUrl()));
    }

    @PostConstruct
    public void init() {
        log.info("### UserLoginFilter 初始化配置");
        // 初始化配置
        SecurityConfig.Login login = securityConfig.getLogin();
        this.setBeanName(this.toString());
        if (StringUtils.isNotBlank(login.getUsernameParameter())) {
            usernameParameter = login.getUsernameParameter();
        }
        if (StringUtils.isNotBlank(login.getPasswordParameter())) {
            passwordParameter = login.getPasswordParameter();
        }
        if (StringUtils.isNotBlank(login.getCaptchaParameter())) {
            captchaParameter = login.getCaptchaParameter();
        }
        if (login.getPostOnly() != null) {
            postOnly = login.getPostOnly();
        }
        this.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
        this.setAuthenticationFailureHandler(customAuthenticationFailureHandler);

//        this.setSessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        // TODO 需要防止用户重复登录

        // 获取用户登录信息
        UserLoginToken userLoginToken;
        if (securityConfig.getLogin().getJsonDataSubmit()) {
            // 使用Json方式提交数据
            String json = IOUtils.toString(request.getReader());
            UserInfo userInfo = JacksonMapper.nonEmptyMapper().fromJson(json, UserInfo.class);
            userLoginToken = new UserLoginToken(userInfo.getUsername(), userInfo.getPassword(), userInfo.getCaptcha());
        } else {
            // 使用Parameter提交数据
            String username = StringUtils.trimToEmpty(request.getParameter(usernameParameter));
            String password = StringUtils.trimToEmpty(request.getParameter(passwordParameter));
            String captcha = StringUtils.trimToEmpty(request.getParameter(captchaParameter));
            userLoginToken = new UserLoginToken(username, password, captcha);
        }

        // 设置用户 "details" 属性
        userLoginToken.setDetails(authenticationDetailsSource.buildDetails(request));
        log.info("### 用户登录开始，构建UserLoginToken [{}]", userLoginToken.toString());
        // 验证登录
        return this.getAuthenticationManager().authenticate(userLoginToken);
    }

    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Data
    private static class UserInfo implements Serializable {
        private String username;
        private String password;
        private String captcha;
    }
}
